
#include "linux_def.h"
#include "core.h"


array_t *array_create(pool_t *p, int n, size_t size)
{
	array_t	*a;

	a = palloc(p, sizeof(array_t));
	if (a == NULL) {
		return NULL;
	}

	a->elts = palloc(p, n * size);
	if (a->elts == NULL) {
		return NULL;
	}

	a->nelts = 0;
	a->size = size;
	a->nalloc = n;
	a->pool = p;

	return a;
}


void array_destroy(array_t *a)
{
	pool_t  *p;

	p = a->pool;

	if ((void*) a->elts + a->size * a->nalloc == p->last) {
		p->last -= a->size * a->nalloc;
	}

	if ((void*) a + sizeof(array_t) == p->last) {
		p->last = (u_char *) a;
	}
}


void *array_push(array_t *a)
{
	void	*elt, *new;
	size_t	size;
	pool_t	*p;

	if (a->nelts == a->nalloc) {
		size = a->size * a->nalloc;
		p = a->pool;

		if ((void*) a->elts + size == p->last && p->last + a->size <= p->end)
		{
			p->last += a->size;
			a->nalloc++;
		} else {
			new = palloc(p, 2 * size);
			if (new == NULL) {
				return NULL;
			}

			memcpy(new, a->elts, size);
			a->elts = new;
			a->nalloc *= 2;
		}
	}

	elt = (u_char *) a->elts + a->size * a->nelts;
	a->nelts++;

	return elt;
}


void *array_push_n(array_t *a, int n)
{
	void	*elt, *new;
	size_t	size;
	int	nalloc;
	pool_t	*p;

	size = n * a->size;

	if (a->nelts + n > a->nalloc) {
		p = a->pool;
		if ((void*) a->elts + a->size * a->nalloc == p->last
			&& p->last + size <= p->end)
		{
			p->last += size;
			a->nalloc += n;
		}else{
			nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
			new = palloc(p, nalloc * a->size);
			if (new == NULL) {
				return NULL;
			}

			memcpy(new, a->elts, a->nelts * a->size);
			a->elts = new;
			a->nalloc = nalloc;
		}
	}

	elt = (u_char *) a->elts + a->size * a->nelts;
	a->nelts += n;

	return elt;
}

